package jmine.tec.web.servlet.cipher.impl;

import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import jmine.tec.web.servlet.cipher.SecureCommunicationHandler;

/**
 * {@link SecureCommunicationHandler} para comunicacao simetrica
 * 
 * @author takeshi
 */
public class SymetricSecureCommunicationHandlerImpl extends SecureCommunicationHandlerImpl implements SecureCommunicationHandler {

    private final byte[] encodedKey;

    /**
     * C'tor
     * 
     * @param theKey a {@link Key}
     * @param chunkSize int
     * @param cipher {@link Cipher}
     */
    public SymetricSecureCommunicationHandlerImpl(Key theKey, int chunkSize, Cipher cipher) {
        super(theKey, theKey, chunkSize, cipher);
        this.encodedKey = theKey.getEncoded();

    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Object writeReplace() throws ObjectStreamException {
        return new SymetricSecureCommunicationSpec(encodedKey, this.getChunkSize(), this.getAlgorithm());
    }

    /**
     * Estado serializado do {@link SymetricSecureCommunicationHandlerImpl}
     * 
     * @author takeshi
     */
    private static class SymetricSecureCommunicationSpec implements Serializable {
        private final byte[] encodedKey;

        private final int chunkSize;

        private final String cipherName;

        /**
         * C'tor
         * 
         * @param encodedKey array de bytes com a spec da chave
         * @param chunkSize int
         * @param cipherName String
         */
        public SymetricSecureCommunicationSpec(byte[] encodedKey, int chunkSize, String cipherName) {
            super();
            this.encodedKey = encodedKey;
            this.chunkSize = chunkSize;
            this.cipherName = cipherName;
        }

        /**
         * Desserializa de volta o {@link SecureCommunicationHandlerImpl}
         * 
         * @return Object
         * @throws ObjectStreamException e
         */
        protected Object readResolve() throws ObjectStreamException {
            try {
                DESKeySpec spec = new DESKeySpec(encodedKey);
                SecretKeyFactory fac = SecretKeyFactory.getInstance("DES");
                return new SymetricSecureCommunicationHandlerImpl(fac.generateSecret(spec), chunkSize, Cipher.getInstance(cipherName));
            } catch (NoSuchAlgorithmException e) {
                throw new InvalidObjectException(e.getMessage());
            } catch (NoSuchPaddingException e) {
                throw new InvalidObjectException(e.getMessage());
            } catch (InvalidKeyException e) {
                throw new InvalidObjectException(e.getMessage());
            } catch (InvalidKeySpecException e) {
                throw new InvalidObjectException(e.getMessage());
            }
        }

    }

}
